
#include "gtest/gtest.h"

#include "cooperative-condition.h"
#include "cooperative-mutex.h"
#include "fiber-env.h"

using namespace std;
using namespace dulymoo;

namespace {

    struct context_t {
        vector<int> numbers;
        CooperativeMutex lock;
        CooperativeCondition cond;

        context_t() : numbers(), lock(), cond(lock)
        {
        }
    };

    void fiber1(void* arg)
    {
        context_t *context = reinterpret_cast<context_t*>(arg);

        context->numbers.push_back(1);
        context->cond.Acquire();
        context->numbers.push_back(2);
        FiberEnv::Yield();
        context->numbers.push_back(4);
        context->cond.Wait();
        context->numbers.push_back(8);
        context->cond.Release();
        context->numbers.push_back(9);
    }

    void fiber2(void* arg)
    {
        context_t *context = reinterpret_cast<context_t*>(arg);

        context->numbers.push_back(3);
        context->cond.Acquire();
        context->numbers.push_back(5);
        context->cond.Signal();
        context->numbers.push_back(6);
        context->cond.Release();
        context->numbers.push_back(7);
    }

    TEST(CooperativeCondition, General) {
        FiberEnv env;

        context_t context;

        EXPECT_TRUE(env.Initialize());
        EXPECT_TRUE(env.AddFiber(fiber1, (void*)(&context)));
        EXPECT_TRUE(env.AddFiber(fiber2, (void*)(&context)));
        EXPECT_TRUE(env.Start(1));
        env.Stop();
        env.Finalize();

        EXPECT_EQ(9, context.numbers.size());
        for (int i=0; i<9; ++i)
            EXPECT_EQ(i+1, context.numbers[i]);
    }
}  // namespace <anonymous>

